// 导入中间件
const createError = require('http-errors') // 错误处理
const express = require('express') // express
const path = require('path') // path
const cookieParser = require('cookie-parser') // 解析cookie 值存放在 req.cookies
const logger = require('morgan') // 日志
const fs = require('fs') // fs
const session = require('express-session') // 引入 session 相关
// 引入 redis 相关
const RedisStore = require('connect-redis')(session)
const redisClient = require('./db/redis')
const { SECRET } = require('./constants')

// 导入表创建
require('./db/sync')

// 导入路由
const indexRouter = require('./routes')
const userRouter = require('./routes/user')

// 调用 express() 方法 返回服务端实例
const app = express()

// 处理动态资源（页面）返回
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')

/* 注册中间件 */
// 日志打印配置 - 写入本地 log
// 创建一个写入流 (in append mode)
const accessLogStream = fs.createWriteStream(path.join(__dirname, 'log/access.log'), { flags: 'a' })
app.use(logger('combined', { stream: accessLogStream }))
// 处理接收请求参数 req.body 为对象格式
app.use(express.json()) // json
app.use(express.urlencoded({ extended: false })) // form data
// cookie 解析注册
app.use(cookieParser())
// 注册保存登录状态的中间件
/*
1. name - cookie的名字（原属性名为 key）。（默认：’connect.sid’）
2. store - session存储实例
3. secret - 用它来对session cookie签名，防止篡改
4. cookie - session cookie设置 （默认：{ path: ‘/‘, httpOnly: true,secure: false, maxAge: null }）
5. genid - 生成新session ID的函数 （默认使用uid2库）
6. rolling - 在每次请求时强行设置cookie，这将重置cookie过期时间（默认：false）
7. resave - 强制保存session即使它并没有变化 （默认： true, 建议设为：false）
8. proxy - 当设置了secure cookies（通过”x-forwarded-proto” header ）时信任反向代理。当设定为true时，
”x-forwarded-proto” header 将被使用。当设定为false时，所有headers将被忽略。当该属性没有被设定时，将使用Express的trust proxy。
9. saveUninitialized - 强制将未初始化的session存储。当新建了一个session且未设定属性或值时，它就处于未初始化状态。在设定一个cookie前，这对于登陆验证，减轻服务端存储压力，权限控制是有帮助的。（默认：true）
10. unset - 控制req.session是否取消（例如通过 delete，或者将它的值设置为null）。这可以使session保持存储状态但忽略修改或删除的请求（默认：keep）
* */
app.use(
  session({
    name: 'userId',
    resave: false,
    saveUninitialized: false,
    secret: SECRET, // 用于生成无关紧要的userId的 - 必填
    cookie: { path: '/', httpOnly: true, maxAge: 24 * 60 * 60 * 1000 },
    store: new RedisStore({ client: redisClient })
  })
)

// 静态资源处理
app.use(express.static(path.join(__dirname, '../public')))
// 注册路由
app.use('/', indexRouter)
app.use('/api/user', userRouter)

// 捕获404并转发给错误处理
app.use(function (req, res, next) {
  next(createError(404))
})

// 错误处理
app.use(function (err, req, res, next) {
  // 设置错误信息 仅在 development 开发模式下
  res.locals.message = err.message
  res.locals.error = req.app.get('env') === 'development' ? err : {}

  // 渲染错误到页面
  res.status(err.status || 500)
  res.render('error')
})

module.exports = app
